/*
 * BeanTreeNode.java
 */

package xq.ide.node;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.NoSuchElementException;
import javax.swing.tree.TreeNode;
import org.apache.log4j.Logger;
import xq.util.LoggerUtil;

/**
 *
 * @author Robert.P.Thornton
 */
public class BeanTreeNode extends DataTreeNode {

	private static final Logger logger = LoggerUtil.getClassLogger();
	
	private Class nodeType;
	private BeanInfo beanInfo;
	private List<PropertyDescriptor> fields;

	public BeanTreeNode(DataTreeNode parentNode, Object nodeData, int nodeIndex) {
		super(parentNode, nodeData, nodeIndex);
		this.fields = new ArrayList<PropertyDescriptor>();
		if (nodeData != null) {
			this.nodeType = nodeData.getClass();
			try {
				this.beanInfo = Introspector.getBeanInfo(nodeType);
				if (beanInfo.getPropertyDescriptors() != null) {
					for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
						if (!pd.getName().matches("class")) {
							fields.add(pd);
						}
					}
				}
			} catch (Throwable thrown) {
				logger.warn(thrown.toString(), thrown);
			}
		}
	}

	public BeanTreeNode(Object o) {
		this(null, o, 0);
	}

	@Override
	public TreeNode getChildAt(int childIndex) {
		TreeNode childNode = null;
		try {
			Method m = fields.get(childIndex).getReadMethod();
			Object childData = m.invoke(nodeData);
			if (childData instanceof Collection) {
				return new ListTreeNode(this, fields.get(childIndex).getName(), childData, childIndex);
			} else {
				return new BeanTreeNode(this, childData, childIndex);
			}
		} catch (Throwable thrown) {
			logger.warn(thrown.toString(), thrown);
		}
		return childNode;
	}

	@Override
	public int getChildCount() {
		return fields.size();
	}

	@Override
	public boolean getAllowsChildren() {
		return fields.size() > 0;
	}

	@Override
	public boolean isLeaf() {
		return fields.size() == 0;
	}

	@Override
	public Enumeration children() {
		return new Enumeration() {

			int index = 0;

			@Override
			public boolean hasMoreElements() {
				return index < fields.size();
			}

			@Override
			public Object nextElement() {
				if (hasMoreElements()) {
					return getChildAt(index++);
				} else {
					throw new NoSuchElementException();
				}
			}
		};
	}

	@Override
	public String toString() {
		return nodeType == null ? "<null>" : nodeType.getSimpleName();
	}
}
